﻿using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using MavlinkDebugger.PacketViewer;

namespace MavlinkPacketViewer.PacketViewer
{
    public abstract class PropertyItem
    {
        private object _value;

        public PropertyItem(object value)
        {
            _value = value;
        }

        public abstract  Type PropertyType { get; }

        public abstract bool CanWrite { get; }

        public abstract string Name { get; }

        public abstract string Category { get; }

        public abstract string DisplayName { get; }

        public  object Value
        {
            get { return _value; }
        }

        public abstract string Description
        {
            get ; 
         
        }
    }


    public abstract class MemberItem<T> : PropertyItem where T : MemberInfo
    {
        protected bool _readOnly = false;
        protected T _memberInfo;
        private string _displayName;
        private string _category;
        private string _description;

        protected MemberItem(T info, object value) : base(value)
        {
            _memberInfo = info;
        }

       

        public bool ReadOnly
        {
            get { return _readOnly; }
            internal set { _readOnly = value; }
        }

        public override string DisplayName
        {
            get
            {
                if (string.IsNullOrEmpty(_displayName))
                {
                    _displayName =  Name;
                }

                return _displayName;
            }
        }

        public override string Category
        {
            get
            {
                if (string.IsNullOrEmpty(_category))
                {
                    var attr =AttributeHelper.GetAttribute<CategoryAttribute>(_memberInfo);
                    if (attr != null && !string.IsNullOrEmpty(attr.Category))
                        _category = attr.Category;
                    else
                        _category = "Members";
                }
                return _category;
            }
        }

        public override string Name
        {
            get { return _memberInfo.Name; }
        }

        public override string Description
        {
            get { return _description ?? (_description = GetSummaryForMemberFromMetaFile(_memberInfo)); }
        }

        private string GetSummaryForMemberFromMetaFile(T info)
        {
            var metaDoc = XDocument.Load("Mavlink_Silverlight3.XML");

            var memberMeta = metaDoc.Descendants(XName.Get("member"));

            var key = info.DeclaringType.Name + "." + info.Name;

            var baz = memberMeta.Where(x => x.Attribute(XName.Get("name")).Value.Contains(key));


            if (baz.Count() > 1)
                return "Error - more than one match in Meta file";

            if (baz.Count() == 0)
                return "No description for: " + info.Name;

            var memberElement = baz.Single().Descendants().SingleOrDefault(n => n.Name == XName.Get("summary"));

            var memberDescription = memberElement.Value.TrimStart();

            // I'm sure this is do-able in the framework?
            var shortTypeName = PropertyType.Name.Split('.').Last();

            return string.Format("{0} ({1})\n\n{2}", info.Name, shortTypeName, memberDescription);
        }
    }






	/// <summary>
	/// PropertyItem hold a reference to an individual property in the propertygrid
	/// </summary>
    public sealed class PropertyInfoItem : MemberItem<PropertyInfo>
	{

        public PropertyInfoItem(object value, PropertyInfo propertyInfo, bool readOnly)
            : base(propertyInfo,value)
        {
			_memberInfo = propertyInfo;
			_readOnly = readOnly;
		}

        public override Type PropertyType
        {
            get { return _memberInfo.PropertyType; }
        }

        public override bool CanWrite
        {
            get { return _memberInfo.CanWrite && !_readOnly; }
        }
	}




    public sealed class FieldItem : MemberItem<FieldInfo>
    {
        public FieldItem(object value, FieldInfo fieldInfo, bool readOnly)
            : base(fieldInfo,value)
        {
            _memberInfo = fieldInfo;
            _readOnly = readOnly;
        }

        public override Type PropertyType
        {
            get { return _memberInfo.FieldType; }
        }

        public override bool CanWrite
        {
            get { return !_readOnly; }
        }
    }
}
